// This file is licensed under the Elastic License 2.0. Copyright 2021 StarRocks Limited.

#pragma once

#include <cstdint>

#include "column/column.h"
#include "column/fixed_length_column.h"

namespace starrocks::vectorized {

class ArrayColumn final : public ColumnFactory<Column, ArrayColumn> {
    friend class ColumnFactory<Column, ArrayColumn>;

public:
    using ValueType = void;

    ArrayColumn(ColumnPtr elements, UInt32Column::Ptr offests);

    ArrayColumn(const ArrayColumn& rhs)
            : _elements(rhs._elements->clone_shared()),
              _offsets(std::static_pointer_cast<UInt32Column>(rhs._offsets->clone_shared())) {}

    ArrayColumn(ArrayColumn&& rhs) noexcept : _elements(std::move(rhs._elements)), _offsets(std::move(rhs._offsets)) {}

    ArrayColumn& operator=(const ArrayColumn& rhs) {
        ArrayColumn tmp(rhs);
        this->swap_column(tmp);
        return *this;
    }

    ArrayColumn& operator=(ArrayColumn&& rhs) noexcept {
        ArrayColumn tmp(std::move(rhs));
        this->swap_column(tmp);
        return *this;
    }

    ~ArrayColumn() override = default;

    bool is_array() const override { return true; }

    const uint8_t* raw_data() const override;

    uint8_t* mutable_raw_data() override;

    size_t size() const override;

    size_t capacity() const override;

    size_t type_size() const override { return sizeof(DatumArray); }

    size_t byte_size() const override { return _elements->byte_size() + _offsets->byte_size(); }
    size_t byte_size(size_t from, size_t size) const override;

    size_t byte_size(size_t idx) const override;

    void reserve(size_t n) override;

    void resize(size_t n) override;

    void assign(size_t n, size_t idx) override;

    void append_datum(const Datum& datum) override;

    void append(const Column& src, size_t offset, size_t count) override;

    void append_selective(const Column& src, const uint32_t* indexes, uint32_t from, uint32_t size) override;

    void append_value_multiple_times(const Column& src, uint32_t index, uint32_t size) override;

    bool append_nulls(size_t count) override;

    bool append_strings(const std::vector<Slice>& strs) override { return false; }

    size_t append_numbers(const void* buff, size_t length) override { return -1; }

    void append_value_multiple_times(const void* value, size_t count) override;

    void append_default() override;

    void append_default(size_t count) override;

    void remove_first_n_values(size_t count) override {}

    uint32_t max_one_element_serialize_size() const override;

    uint32_t serialize(size_t idx, uint8_t* pos) override;

    uint32_t serialize_default(uint8_t* pos) override;

    void serialize_batch(uint8_t* dst, Buffer<uint32_t>& slice_sizes, size_t chunk_size,
                         uint32_t max_one_row_size) override;

    const uint8_t* deserialize_and_append(const uint8_t* pos) override;

    void deserialize_and_append_batch(std::vector<Slice>& srcs, size_t chunk_size) override;

    uint32_t serialize_size(size_t idx) const override;

    MutableColumnPtr clone_empty() const override;

    size_t filter_range(const Filter& filter, size_t from, size_t to) override;

    int compare_at(size_t left, size_t right, const Column& right_column, int nan_direction_hint) const override;

    void crc32_hash_at(uint32_t* seed, int32_t idx) const override;
    void fnv_hash_at(uint32_t* seed, int32_t idx) const override;
    void fnv_hash(uint32_t* hash, uint32_t from, uint32_t to) const override;

    void crc32_hash(uint32_t* hash, uint32_t from, uint32_t to) const override;

    void put_mysql_row_buffer(MysqlRowBuffer* buf, size_t idx) const override;

    std::string get_name() const override { return "array"; }

    Datum get(size_t idx) const override;

    bool set_null(size_t idx) override;

    size_t memory_usage() const override { return _elements->memory_usage() + _offsets->memory_usage(); }

    size_t shrink_memory_usage() const override {
        return _elements->shrink_memory_usage() + _offsets->shrink_memory_usage();
    }

    size_t container_memory_usage() const override {
        return _elements->container_memory_usage() + _offsets->container_memory_usage();
    }

    size_t element_memory_usage(size_t from, size_t size) const override;

    void swap_column(Column& rhs) override;

    void reset_column() override;

    const Column& elements() const;
    ColumnPtr& elements_column();

    const UInt32Column& offsets() const;
    UInt32Column::Ptr& offsets_column();

    bool is_nullable() const override { return false; }

    std::string debug_item(uint32_t idx) const override;

    std::string debug_string() const override;

    bool reach_capacity_limit() const override {
        return _elements->reach_capacity_limit() || _offsets->reach_capacity_limit();
    }

private:
    ColumnPtr _elements;
    // Offsets column will store the start position of every array element.
    // Offsets store more one data to indicate the end position.
    // For example, [1, 2, 3], [4, 5, 6].
    // The two element array has three offsets(0, 3, 6)
    UInt32Column::Ptr _offsets;
};

} // namespace starrocks::vectorized
